/*
 *  Copyright (C) 2009  Peter Kist & Jan Ripke
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/** \file
* This file contains the definitions (and class implementation) of a very simple logger.
*/

#ifndef __util_logger_h
#define __util_logger_h 1

#include <fstream>
#include <string>

/** \def util_LOG_LEVEL_ERROR
 * \brief log errors that influence execution flow. Invokes util::Logger::error
 */
#define util_LOG_LEVEL_ERROR    1

/** \def util_LOG_LEVEL_WARNING
 * \brief log warnings that (situations that are recoverable and do not influence execution flow).
 * Invokes util::Logger::warning
 */
#define util_LOG_LEVEL_WARNING  2

/** \def util_LOG_LEVEL_INFO
 * \brief log informational messages about the functioning of the program.
          Invokes util::Logger::info
 */
#define util_LOG_LEVEL_INFO     3

/** \def util_LOG_LEVEL_DEBUG
 * \brief log debugging statements that allow developers trace execution of the program.
          Invokes util::Logger::debug
 */
#define util_LOG_LEVEL_DEBUG    4

/** \def util_LOG_LEVEL_TRACE
 * \brief log detailed information about data structures that are used for debugging purposes.
 *        Invokes util::Logger::trace
 */
#define util_LOG_LEVEL_TRACE    5


#ifndef util_LOG_LEVEL
# ifdef _DEBUG
#  define util_LOG_LEVEL util_LOG_LEVEL_TRACE
# else
#  define util_LOG_LEVEL util_LOG_LEVEL_WARNING
# endif
#endif

/* \def util_LOG_LEVEL
 * \brief The default log level that is used when it is not specified on the compiler's command line
 * For Debug builds it defaults to TRACE level and for release builds it defaults to WARNING.
 */

#if util_LOG_LEVEL > 4
# define LOG_TRACE(msg) galaxy::util::Logger::trace(msg)
#else
# define LOG_TRACE(msg)
#endif
#if util_LOG_LEVEL > 3
# define LOG_DEBUG(msg) galaxy::util::Logger::debug(msg)
#else
# define LOG_DEBUG(msg)
#endif
#if util_LOG_LEVEL > 2
# define LOG_INFO(msg) galaxy::util::Logger::info(msg)
#else
# define LOG_INFO(msg)
#endif
#if util_LOG_LEVEL > 1
# define LOG_WARNING(msg) galaxy::util::Logger::warning(msg)
#else
# define LOG_WARNING(msg)
#endif
#if util_LOG_LEVEL > 0
# define LOG_ERROR(msg) galaxy::util::Logger::error(msg)
#else
# define LOG_ERROR(msg)
#endif


namespace galaxy {
    namespace util {

        /** The main logger class.
         * This class offers five different log methods (error, warning, info, debug and trace), each having
         * 2 polymorphic versions (const char * and std::string&).
         * \par
         * Note that these logger methods are not intended to be used directly (although you can). Please 
         * use the defines specified in Logger.h instead.
         * \par
         * For example:
         * \code
         * util::Logger::initialize ("output.log");
         * LOG_ERROR (std::string("cannot open file ") + filename);
         * LOG_WARNING ("socket connection timed out");
         * util::Logger::terminate ();
         * \endcode
         */
        class Logger
        {
            static bool initialized;
            static std::ofstream logstream;

            Logger(void) { };
            ~Logger(void) { if (logstream.good()) logstream.close(); };

        public:

            /** Initialize the logger. This method opens the specified log file.
            * It must be called before the logging methods are used. Failure to do so will crash the log methods
            */
            static void initialize (const char * logfile);
            /** close the logfile that was opened by \b initialize.
            * Calling a log method after terminating the logger will result in a crash
            */
            static void terminate ();

            static void error (char * msg);     /**< \see LOG_ERROR */
            static void warning (char * msg);   /**< \see LOG_WARNING */
            static void info (char * msg);
            static void trace (char * msg);

            static void error (const char * msg);     /**< \see LOG_ERROR */
            static void warning (const char * msg);   /**< \see LOG_WARNING */
            static void info (const char * msg);
            static void trace (const char * msg);

            static void error (std::string& msg);   /**< \see LOG_ERROR */
            static void warning (std::string& msg); /**< \see LOG_WARNING */
            static void info (std::string& msg);
            static void trace (std::string& msg);

            /** Flush any content on the loggers file stream to disk */
            static void flush () { logstream.flush (); };
        };

    } // namespace util
} // namespace galaxy

#endif // __util_logger_h //
